/************************************************************
* @file   gkt_os.h
************************************************************/

#ifndef GKT_OS_H
#define GKT_OS_H

#include "gkt_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/* kernel */

int gkt_kernel_init(void);

void gkt_kernel_start(void);

typedef uint32_t	gkt_ticks_t;
gkt_ticks_t gkt_kernel_get_ticks(void);

/* task */
typedef void	*gkt_thread_t;

typedef void (*gkt_thread_routine_fn)(void *arguments);

typedef enum _gkt_thread_state {
	GKT_THREAD_STATE_INACTIVE = 0,
	GKT_THREAD_STATE_READY,
	GKT_THREAD_STATE_RUNNING,
	GKT_THREAD_STATE_BLOCKED,
	GKT_THREAD_STATE_TERMINATED,
	GKT_THREAD_STATE_ERROR,
	GKT_THREAD_STATE_MAX
} gkt_thread_state_e;

typedef enum _gkt_thread_priority {
	GKT_THREAD_PRIORITY_IDLE = 0,
	GKT_THREAD_PRIORITY_LOW,
	GKT_THREAD_PRIORITY_NORMAL,
	GKT_THREAD_PRIORITY_HIGH,
	GKT_THREAD_PRIORITY_REAL,
	GKT_THREAD_PRIORITY_ISR,
	GKT_THREAD_PRIORITY_MAX
} gkt_thread_priority_e;

#define GKT_THREAD_PRIORITY_BY_NAME_L2(name)	\
	GKT_THREAD_PRIORITY_##name
#define GKT_THREAD_PRIORITY_BY_NAME_L1(name)	\
	GKT_THREAD_PRIORITY_BY_NAME_L2(name)
#define GKT_THREAD_PRIORITY_BY_NAME(name)	\
	GKT_THREAD_PRIORITY_BY_NAME_L1(name)

typedef struct _gkt_thread_extend_attr {
	const char	*name;
	uint32_t	flags;
	void	*stack_mem;
} gkt_thread_extend_attr_s;

/*
 * @brief create new thread/task
 * @params
 *   priority    [in] thread priority
 *   stack_size  [in] thread stack size, aligned in 8-bytes(uint64_t)
 *                    if ZERO, use STACK_MINSIZE instead.
 *   routine     [in] thread routine
 *   arguments   [in] arguments passed to thread routine
 *   extend_attr [in] [optional] extend attr
 */
gkt_thread_t gkt_thread_create(
						gkt_thread_routine_fn routine, 
						void *arguments, 
						gkt_thread_priority_e priority,
						uint32_t stack_size, 
						gkt_thread_extend_attr_s *extend_attr);

int gkt_thread_destroy(gkt_thread_t thread);

/*
 * @brief get current running thread / itself
 */
gkt_thread_t gkt_thread_current(void);

/*
 * @brief get the specified thread state
 */
gkt_thread_state_e gkt_thread_get_state(gkt_thread_t thread);

/*
 * @brief get thread priority
 * @return
 *   [GKT_THREAD_PRIORITY_IDLE, GKT_THREAD_PRIORITY_MAX)
 *   < 0 : error occurs, specified thread does not exist.
 */
int gkt_thread_get_priority(gkt_thread_t thread);

/*
 * @brief set thread priority
 * @return : GKT_SUCCESS or error code
 */
int gkt_thread_set_priority(gkt_thread_t thread, 
				gkt_thread_priority_e priority);

/*
 * @brief pass control to next thread that is in READY state
 */
void gkt_thread_yield(void);

/*
 * @brief suspend/resume execution of a thread
 */
int gkt_thread_suspend(gkt_thread_t thread);
int gkt_thread_resume(gkt_thread_t thread);

/*
 * @brief terminate execution of current running thread (itself)
 */
__NO_RETURN void gkt_thread_exit(uint32_t retval);


/*
 * @brief thread sleeps and waked up in specified time
 *        the real sleep time will be rounded up to time of one tick
 */
void gkt_thread_sleep(uint32_t time_ms);


/* mutex */
#define GKT_MUTEX_RECURSIVE	1U
#define GKT_MUTEX_PRIOINHERIT	2U

typedef void	*gkt_mutex_t;
gkt_mutex_t gkt_mutex_create(uint32_t attr);
void gkt_mutex_destroy(gkt_mutex_t mutex);
int gkt_mutex_lock(gkt_mutex_t mutex, uint32_t timeout);
int gkt_mutex_unlock(gkt_mutex_t mutex);

/*
 * @brief get the thread who owns the mutex object
 */
gkt_thread_t gkt_mutex_get_owner(gkt_mutex_t mutex);


/* Semaphore */
typedef void	*gkt_semaphore_t;

gkt_semaphore_t gkt_semaphore_create(uint32_t max_count, 
						uint32_t initial_count);

void gkt_semaphore_destroy(gkt_semaphore_t sem);

int gkt_semaphore_acquire(gkt_semaphore_t sem, 
						uint32_t timeout);

int gkt_semaphore_release(gkt_semaphore_t sem);

int gkt_semaphore_get_count(gkt_semaphore_t sem);


/* message queue */
typedef void	*gkt_mqueue_t;
gkt_mqueue_t gkt_mqueue_create(uint32_t msg_count, 
					uint32_t msg_size);
void gkt_mqueue_destroy(gkt_mqueue_t mqueue);
int gkt_mqueue_put(gkt_mqueue_t mqueue, 
			const void *message, uint32_t timeout);
int gkt_mqueue_get(gkt_mqueue_t mqueue, 
			void *message, uint32_t timeout);
int gkt_mqueue_get_count(gkt_mqueue_t mqueue);


/* Soft Timer */
typedef void	*gkt_soft_timer_t;

typedef enum _gkt_soft_timer_type {
	GKT_SOFT_TIMER_ONCE = 0,
	GKT_SOFT_TIMER_PERIODIC,
} gkt_soft_timer_type_e;

typedef void (*gkt_soft_timer_callback_fn)(void *arguments);

gkt_soft_timer_t gkt_soft_timer_create(
						gkt_soft_timer_type_e type,
						gkt_soft_timer_callback_fn callback,
						void *arguments);

int gkt_soft_timer_destroy(gkt_soft_timer_t timer);

int gkt_soft_timer_start(gkt_soft_timer_t timer,
			uint32_t interval_ms);

int gkt_soft_timer_stop(gkt_soft_timer_t timer);

#ifdef __cplusplus
}
#endif

#endif	/* GKT_OS_H */

